/* include bsp */
#include "stm32f1xx_hal.h"
#include "stepper_ctrl.h"
#include "elec_part.c"

#include "move.h"
#include <stdio.h>

/**
 * @defgroup 加减速相关内容
 * @{
 */
typedef uint16_t ARR_t;

typedef enum flexible {
    flexible_2 = 2,
    flexible_3 = 3,
    flexible_4 = 4,
    flexible_5 = 5,
    flexible_6 = 6,
    flexible_7 = 7,
    flexible_8 = 8,
}flexible_t;

/**
 * @brief  步进电机加减速系数结构体
 */
typedef struct stepper_celeration_config {
    /****** Speed param ******/
    freq_t freq_min; ///< (hz)
    freq_t freq_max; 
    uint8_t change_point_num;
    uint8_t change_point_interval; ///< (ms) 
    flexible_t flexible;
    /***** Distance param ****/
    uint16_t acceleration_pul_cnt;
    /****** Timer param ******/
    uint16_t psc;
    const ARR_t *celeration_ARR;
    uint8_t delay_time_correction;
    /****** Base param ******/
    stepper_param_config_t *stepper_param_config;
    stepper_sys_config_t *stepper_sys_config;
}stepper_celeration_config_t;

/**
 * @brief S形加减速ARR数据串，用于 X 步进电机，9
 * @note ARR数据串由相应的加减速参数计算得到，计算过程与结果在excel文件中实现
 */
const ARR_t celerarion_S_X9_ARR[] = {
    2779 , 	2284 , 	1879 , 	1547 , 	1276 , 	1053 , 	871 , 	722 , 	600 , 	500 , 	
    418 , 	351 , 	297 , 	252 , 	215 , 	185 , 	160 , 	140 , 	124 , 	110 , 	
    99 , 	90 , 	83 , 	76 , 	71 , 	67 , 	64 , 	61 , 	59 , 	57 , 	
    56 , 	55 , 	54 , 	53 , 	52 , 	51 , 	51 , 	51 , 	50 , 	50 , 
};
stepper_celeration_config_t CELERATION_S_X9_CFG = 
{
    .freq_min = 0,
    .freq_max = 2000,
    .change_point_num = 20,
    .change_point_interval = 80,
    .flexible = flexible_4,
    .acceleration_pul_cnt = 3145, 
    .psc = 639,
    .celeration_ARR = celerarion_S_X9_ARR,
    .delay_time_correction = 40,
    .stepper_param_config = &stp_x_param,
    .stepper_sys_config = &stp_sys_cfg,
};

/**
 * @brief S形加减速ARR数据串，用于 X 步进电机，2
 * @note ARR数据串由相应的加减速参数计算得到，计算过程与结果在excel文件中实现
 */
const ARR_t celerarion_S_X2_ARR[] = {
    3355 , 	2380 , 	1727 , 	1289 , 	996 , 	799 , 	667 , 	579 , 	519 , 	480 , 
};
stepper_celeration_config_t CELERATION_S_X2_CFG = 
{
    .freq_min = 0,
    .freq_max = 250,
    .change_point_num = 5, /* ARR 数组的长度为该值的 2 倍 */
    .change_point_interval = 120,
    .flexible = flexible_2,
    .acceleration_pul_cnt = 135, 
    .psc = 639,
    .celeration_ARR = celerarion_S_X2_ARR,
    .delay_time_correction = 50,
    .stepper_param_config = &stp_x_param,
    .stepper_sys_config = &stp_sys_cfg,
};

static stepper_celeration_config_t *x_celeration_cfg;
static stepper_celeration_config_t *y_celeration_cfg;
static stepper_celeration_config_t *z_celeration_cfg;

/**
 * @}
 */

/**
 * @defgroup 动力机构移动定位相关
 * @{
 */

/**
 * @brief 根据速度选择 stepper_celeration_config_t
 */
static void speed_match_celetation_cfg(stepper_celeration_config_t **cfg, speed_t speed)
{
    switch (speed) {
    case SPEED_9 : 
        *cfg = &CELERATION_S_X9_CFG; 
        break;
    case SPEED_8 :
        //*cfg = &CELERATION_S_X8_CFG; 
        break;
    case SPEED_7 :
    case SPEED_6 :

    case SPEED_2:
        *cfg = &CELERATION_S_X2_CFG;
        break;
    case SPEED_1 : 
        //*cfg = &CELERATION_S_X1_CFG; 
        break;
    }
}

/* 记录存储动力机构活动信息，坐标数据、移动方向、动作状态 */
/* 在初始化中清值；在 move 中设置；在结束后的更新中断回调函数中修改 */
#define MOVING_NOT_REACH 0U
#define STILL_REACH 1U
struct {
    volatile float position;
    volatile uint8_t dir;
    volatile speed_t speed;
    volatile uint8_t reach; /* moving or still */, 
}x_mover, y_mover, z_mover;

/**
 * @brief 坐标记录处理回调函数，每次完成移动指定距离后，会回调该函数，传入移动距离
 */
void x_position_handle_callback(float distance)
{
    printf("x callback\n");
    if (x_mover.dir == DIR_FRONT) {
        x_mover.position += distance;
    } else if (x_mover.dir == DIR_BACK) {
        x_mover.position -= distance;
    }
    x_mover.reach = STILL_REACH;
}
void y_position_handle_callback(float distance)
{
    if (y_mover.dir == DIR_FRONT) {
        y_mover.position += distance;
    } else if (y_mover.dir == DIR_BACK) {
        y_mover.position -= distance;
    }
    y_mover.reach = STILL_REACH;
}
void z_position_handle_callback(float distance)
{
    if (z_mover.dir == DIR_FRONT) {
        z_mover.position += distance;
    } else if (z_mover.dir == DIR_BACK) {
        z_mover.position -= distance;
    }
    z_mover.reach = STILL_REACH;
}

/**
 * @brief X动力机构移动配置初始化
 */
void x_mover_init()
{
    x_move(DIR_BACK, SPEED_5, 500);
    x_mover.position = 0;
    x_mover.reach = STILL_REACH;
    x_position_callback = x_position_handle_callback;
    start_limit_switch_callback = start_limit_switch_handle_callback;
    end_limit_switch_callback = end_limit_switch_handle_callback;
}
void y_mover_init()
{
    y_mover.position = 0;
    y_mover.reach = STILL_REACH;
    y_position_callback = y_position_handle_callback;
    low_limit_switch_callback = low_limit_siwtch_handle_callback;
}
void z_mover_init()
{
    z_mover.position = 0;
    z_mover.reach = STILL_REACH;
    z_position_callback = z_position_handle_callback;
}

/**
 * @brief 驱动动力机构移动指定位移
 * @param dir 动力机构移动方向
 *      @arg DIR_FRONT
 *      @arg DIR_BACK
 * @param speed 动力机构移动速度
 *      @arg SPEED_1
 *      ...
 *      @arg SPEED_9
 * @param distance 指定移动距离 /cm 
 *      @arg min ~ 650.00
 * @retval 执行结果
 */
uint8_t x_move(uint8_t dir, speed_t speed, float distance)
{
    speed_match_celetation_cfg(&x_celeration_cfg, speed);

#define ARR_array       (x_celeration_cfg->celeration_ARR)
#define ARR_array_len   (x_celeration_cfg->change_point_num * 2)
#define interval        (x_celeration_cfg->change_point_interval)
#define all_pul_cnt     ((uint32_t)(distance / x_celeration_cfg->stepper_param_config->distance_pul))
#define delay_pul_cnt   (all_pul_cnt - x_celeration_cfg->acceleration_pul_cnt * 2)
    
    uint32_t delay_time = ((uint32_t)(delay_pul_cnt
        * (1000 + x_celeration_cfg->delay_time_correction * 1000 / x_celeration_cfg->freq_max)
        / x_celeration_cfg->freq_max));
    
    if (all_pul_cnt <= x_celeration_cfg->acceleration_pul_cnt * 2)
        return ERR_DISTANCE_TOO_SHORT;
    if (all_pul_cnt > MAX_DISRACE)
        return ERR_DISTANCE_TOO_LONG;
    #if 0
    printf("all_pul_cnt:%ld\n", all_pul_cnt);
    printf("delay_pul_cnt:%ld\n", delay_pul_cnt);
    printf("delay_time:%d\n", delay_time);
    #endif
    
    /* 设置 mover，设置方向、位移、速度, 启动 */
    x_mover.dir = dir;
    x_mover.reach = MOVING_NOT_REACH;
    x_mover.speed = speed;
    stepper_dir(STEPPER_X_INDEX, dir); 
    stepper_make_steps(STEPPER_X_INDEX, all_pul_cnt);
    stepper_pwm_freq_byARR(STEPPER_X_INDEX, ARR_array[0]);
    stepper_pwm_state(STEPPER_X_INDEX, STEPPER_STATE_RUN);

    for (int i = 0; i < ARR_array_len; i ++) {      /* 加速阶段 */
        //HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_9);
        stepper_pwm_freq_byARR(STEPPER_X_INDEX, ARR_array[i]);
        HAL_Delay(interval);
    }

    HAL_Delay(delay_time);      /* 匀速阶段 */

    for (int i = ARR_array_len - 1; i > 0; i --) {      /* 减速阶段 */
        //HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_9);
        stepper_pwm_freq_byARR(STEPPER_X_INDEX, ARR_array[i]);
        HAL_Delay(interval);
    }

    while(MOVING_NOT_REACH == x_mover.reach) {} /* 只有完成脉冲数，产生回调 */

    //stepper_pwm_state(STEPPER_X_INDEX, STEPPER_STATE_STOP);
    printf("x postion:%f\n", x_mover.position);

    return SUCCESS;
}

void y_move(uint8_t dir, uint8_t speed, float distance)
{

}

void z_move(uint8_t dir, uint8_t speed, float distance)
{

}

/**
 * @}
 */

/**
 * @defgroup 移动限位相关
 * @{
 */

/**
 * @brief 限位开关触发处理回调函数，到达限位处后移动停止或反馈
 */
void start_limit_switch_handle_callback(void)
{
    uint32_t step_num = 0;
    stepper_pwm_state(STEPPER_X_INDEX, STEPPER_STATE_STOP);
    stepper_en(STEPPER_X_INDEX, STEPPER_EN_DISABLE);
    x_mover_position
    if (x_mover.position > )
}
void end_limit_switch_handle_callback(void)
{

}
void low_limit_switch_handle_callback(void)
{

}

/**
 * @}
 */